use crossterm::event::{read, Event::Key, KeyCode::Char};
use crossterm::event::{Event, KeyCode, KeyEvent, KeyEventKind, KeyModifiers};
use std::cmp::min;
use std::env;
use std::io::Error;

mod terminal;
mod view;
mod buffer;

use terminal::{Position, Size, Terminal};
use view::View;

#[derive(Default)]
pub struct Editor {
    should_quit: bool,
    location: Location,
    view: View,
}
impl Editor {
    pub fn run(&mut self) {
        Terminal::initialize().unwrap();
        self.handle_args().unwrap();
        Terminal::move_caret(Position { col: 0, row: 0 }).unwrap();
        let result = self.repl();
        Terminal::terminate().unwrap();
        result.unwrap();
    }
    fn repl(&mut self) -> Result<(), Error> {
        loop {
            self.refresh_screen().unwrap();
            if self.should_quit {
                break;
            }
            let event = read()?;
            self.evalute_event(&event)?;
        }
        Ok(())
    }
    fn move_points(&mut self, keycode: KeyCode) -> Result<(), Error> {
        let Location { mut x, mut y } = self.location;
        let Size { width, height } = Terminal::size()?;
        match keycode {
            KeyCode::Left => {
                x = x.saturating_sub(1);
            }
            KeyCode::Right => {
                x = min(x.saturating_add(1), width.saturating_sub(1));
            }
            KeyCode::Up => {
                y = y.saturating_sub(1);
            }
            KeyCode::Down => {
                y = min(height.saturating_sub(1), y.saturating_add(1));
            }
            KeyCode::Home => {
                x = 0;
            }
            KeyCode::End => {
                x = width.saturating_sub(1);
            }
            KeyCode::PageUp => {
                y = 0;
            }
            KeyCode::PageDown => {
                y = y.saturating_sub(1);
            }
            _ => (),
        }
        self.location = Location { x, y };
        Ok(())
    }
    fn evalute_event(&mut self, event: &Event) -> Result<(), Error> {
        if let Key(KeyEvent {
            code,
            modifiers,
            kind: KeyEventKind::Press,
            ..
        }) = event
        {
            match code {
                KeyCode::Left
                | KeyCode::Right
                | KeyCode::Up
                | KeyCode::Down
                | KeyCode::Home
                | KeyCode::End
                | KeyCode::PageUp
                | KeyCode::PageDown => {
                    self.move_points(*code)?;
                }

                Char(c) => {
                    if *modifiers != KeyModifiers::CONTROL && *modifiers != KeyModifiers::ALT {
                        Terminal::print_c(c).unwrap();
                        Terminal::execute().unwrap();
                    }
                    if *c == 'q' && *modifiers == KeyModifiers::CONTROL {
                        self.should_quit = true;
                    }
                }
                _ => (), // KeyCode::Tab => todo!(),
                         // KeyCode::BackTab => todo!(),
                         // KeyCode::Delete => todo!(),
                         // KeyCode::Insert => todo!(),
                         // KeyCode::F(_) => todo!(),
                         // KeyCode::Backspace => todo!(),
                         // KeyCode::Enter => todo!(),
                         // KeyCode::Null => todo!(),
                         // KeyCode::Esc => todo!(),
                         // KeyCode::CapsLock => todo!(),
                         // KeyCode::ScrollLock => todo!(),
                         // KeyCode::NumLock => todo!(),
                         // KeyCode::PrintScreen => todo!(),
                         // KeyCode::Pause => todo!(),
                         // KeyCode::Menu => todo!(),
                         // KeyCode::KeypadBegin => todo!(),
                         // KeyCode::Media(_) => todo!(),
                         // KeyCode::Modifier(_) => todo!(),
            }
        }
        Ok(())
    }
    fn refresh_screen(&self) -> Result<(), Error> {
        //未搞懂为什么在此处隐藏光标
        Terminal::hiden_caret()?;
        Terminal::move_caret(Position::default())?;
        if self.should_quit {
            Terminal::clean_screen()?;
            Terminal::print("Goodbye")?;
            // println!("goodbye");
        } else {
            // View::render()?;
            Terminal::move_caret(Position {
                col: self.location.x,
                row: self.location.y,
            })?;
        }
        Terminal::show_caret()?;
        Terminal::execute()?;
        Ok(())
    }
    fn handle_args(&mut self) ->Result<(),Error>{
        let args:Vec<String>=env::args().collect();
        let file_name_opt= args.get(1);
        self.view.load(file_name_opt)
    }
}

#[derive(Default, Clone, Copy)]
pub struct Location {
    pub y: usize,
    pub x: usize,
}
